package com.lifeonwalden.dsg.service;

import com.lifeonwalden.dsg.bean.DateGenerateRule;
import com.lifeonwalden.dsg.constant.HolidayAdjustRule;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Collectors;

public interface DateSeriesGenerator {
    /**
     * 根据规则生成日期序列
     *
     * @param rule
     * @param dateService
     * @return
     */
    static List<Date> generate(DateGenerateRule rule, DateService dateService) {
        if (rule.getStep() <= 0) {
            throw new RuntimeException("Invalid step value, it must bigger then zero.");
        }

        if (null == rule.getStart() || null == rule.getEnd() || rule.getStart().compareTo(rule.getEnd()) >= 0) {
            throw new RuntimeException("Please provide valid period for start and end.");
        }

        switch (rule.getFrequency()) {
            case DAY: {
                return InnerDayFrequencyUtil.generate(rule, dateService);
            }
            case WEEK: {
                return InnerWeekFrequencyUtil.generate(rule, dateService);
            }
            case MONTH: {
                return InnerMonthFrequencyUtil.generate(rule, dateService);
            }
            case QUARTER: {
                return InnerQuarterFrequencyUtil.generate(rule, dateService);
            }
            case YEAR: {
                return InnerYearFrequencyUtil.generate(rule, dateService);
            }
        }

        return Collections.emptyList();
    }

    /**
     * 基于当前日期序列，根据T+n生成新的日期序列
     *
     * @param dateList          原始日期序列
     * @param dateService       假期日期服务
     * @param holidayAdjustRule 假期调整规则
     * @param n                 T+n 自然日
     * @return
     */
    static List<Date> generate(List<Date> dateList, DateService dateService, HolidayAdjustRule holidayAdjustRule, int... n) {
        TreeSet<Date> dateSet = new TreeSet<>();

        for (Date date : dateList) {
            Instant dateInstant = date.toInstant();
            for (int i : n) {
                dateSet.add(InnerUtil.adjustForHoliday(holidayAdjustRule, Date.from(dateInstant.plus(i, ChronoUnit.DAYS)), dateService));
            }
        }
        return dateSet.stream().collect(Collectors.toList());
    }

    /**
     * 基于当前日期序列，根据T+n生成新的非节假日日期序列
     *
     * @param dateList    原始日期序列
     * @param dateService 假期日期服务
     * @param n           T+n 交易日
     * @return
     */
    static List<Date> generate(List<Date> dateList, DateService dateService, int... n) {
        TreeSet<Date> dateSet = new TreeSet<>();

        for (Date date : dateList) {
            for (int i : n) {
                dateSet.add(dateService.moveN(date, i));
            }
        }
        return dateSet.stream().collect(Collectors.toList());
    }

    /**
     * 基于当前日期序列，生成后续连续数个交易日的日期序列
     *
     * @param dateList    原始日期序列
     * @param dateService 假期日期服务
     * @param n           后续n个连续交易日
     * @param includeBase 是否包含基准日
     * @return
     */

    static List<Date> generate(List<Date> dateList, DateService dateService, int n, boolean includeBase) {
        TreeSet<Date> dateSet = new TreeSet<>();

        for (Date date : dateList) {
            if (includeBase) {
                dateSet.add(date);
            }

            Date dateAfterBase = date;
            for (int i = 1; i <= n; i++) {
                dateAfterBase = dateService
                        .fetchNonHolidayOrNext(
                                Date.from(dateAfterBase.toInstant().plus(1, ChronoUnit.DAYS)));
                dateSet.add(dateAfterBase);
            }
        }
        return dateSet.stream().collect(Collectors.toList());
    }
}
